package org.tigr.htc.cmd;

/*
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

import java.util.Collection;
import java.util.Hashtable;
import java.util.Vector;

import org.apache.log4j.Logger;
import org.exolab.castor.persist.spi.Complex;
import org.tigr.htc.persist.IPersist;
import org.tigr.htc.persist.PersistFactory;

/**
 * The <b>TaskGroup</b> data structure to organize the tasks associated with array jobs
 * submitted to the grid. This class also provides utility methods to query the tasks of a 
 * command.
 *
 */

public class TaskGroup {
    static Logger log = Logger.getLogger("org.tigr.htc.cmd.TaskGroup");

    /** The field <code>tasks</code> */
    private Hashtable tasksHash;
    private Vector tasks;
    
    public long cmd;

    static protected IPersist persist = PersistFactory.getIPersist();

    private boolean persisted = false;

    /**
     * Creates a new <code>Command</code> instance with default value.
     */
    public TaskGroup() {
        tasksHash = new Hashtable();
        tasks = new Vector();
    }

    /**
     * The method <code>getCmdId</code> returns the command ID associated with this
     * task group.
     * 
     * @return a <code>long</code> value representing the command ID
     */
    public long getCmdId() {
        return cmd;
    }

    /**
     * The method <code>setCmdId</code> sets the value of the command ID field.
     * 
     * @param p_cmd a <code>long</code> value representing the command ID
     */
    public void setCmdId(long p_cmd) {
        cmd = p_cmd;
    }

    // check hashtable
    /**
     * The method <code>get</code> returns the task associated with the specified index
     * 
     * @param p_key a <code>int</code> representing the task index
     * @return a <code>Task</code> which represents the specific task
     */
    public Task get(Integer p_key) {
        Task task = (Task) tasksHash.get(p_key);

        // check if task in already in hash
        if (persisted) {
            if (task == null) {
                task = (Task) persist.find(new Complex(new Long(cmd), p_key), Task.class);
            }
        }

        return task;
    }

    /**
     * The method <code>put</code> adds the specified task to the task group. Also if this
     * groups ahs been presisted the method updated the task group in the data store
     * 
     * @param p_keya <code>int</code> representing the task index
     * @param a <code>Task</code> which represents the specific task
     */
    public void put(Integer p_key, Task p_task) {
        // decide if we need to update or create
        if (persisted) {
            if (tasksHash.containsKey(p_key)) { // update
                persist.update(p_task);
            }
            else {
                persist.create(p_task);
            }
        }

        tasksHash.put(p_key, p_task);
        
        // Since, this put methos is bein called in taskFinished, taskFailure
        // methods of Command object, only adding the task to the tasks vector
        // if doesn't exists already.
        if (! tasks.contains(p_task))  {
        	tasks.add(p_task);
        }
    }

    /**
     * The method <code>values</code> returns the collection of tasks in this group
     * 
     * @return a <code>Collection</code> that contains all the tasks associated with this
     * group
     */
    public Collection values() {
        return tasksHash.values();
    }

    public Vector getTasks () {
        if (log.isDebugEnabled()) {
            log.debug("Returning tasks: " + tasks.size());
        }
        return tasks;
    }
    
    public void setTasks (Vector tasks) {
        if (log.isDebugEnabled()) {
            log.debug("Setting tasks: " + tasks);
        }
        this.tasks = tasks;
    }
    
    /**
     * The method <code>isPersisted</code> returns the persisted state of this task group
     * 
     * @return a <code>boolean</code> of true if the task group has been persisted, false 
     * otherwise
     */
    public boolean isPersisted() {
        return persisted;
    }

    /**
     * The method <code>setPersisted</code> sets the persisted state of this task group.
     * 
     * @param p_persisted a <code>boolean</code> value representing the persisted state
     */
    public void setPersisted(boolean p_persisted) {
        persisted = p_persisted;
    }

    
    /**
     * <code>toString</code> returns a string representation of the task group.
     *
     * @return a <code>String</code> value
     */
    public String toString() {
        return "TaskGroup for command with ID: " + cmd + ". Number of tasks: " + tasks.size();
    }
    
    /**
     * <code>toString</code> returns a xml representation of the task group using the
     * CommandHelper to do the conversion.
     *
     * @return a <code>String</code> value
     */
    public String toXMLString() {
        return CommandHelper.getInstance().marshal(this);
    }
}
